/*
 * Copyright 2012 Faculty of Informatics - Masaryk University.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cz.muni.fi.pa165.creatures.rest.client;

import cz.muni.fi.pa165.creatures.dto.RegionDTO;
import cz.muni.fi.pa165.creatures.dto.WeaponDTO;
import cz.muni.fi.pa165.creatures.rest.client.services.CRUDService;
import cz.muni.fi.pa165.creatures.rest.client.services.impl.RegionCRUDServiceImpl;
import cz.muni.fi.pa165.creatures.rest.client.services.impl.WeaponCRUDServiceImpl;
import cz.muni.fi.pa165.creatures.rest.client.utils.CommandLineValidator;
import cz.muni.fi.pa165.creatures.rest.client.utils.DTOBuilder;
import cz.muni.fi.pa165.creatures.rest.client.utils.OptionsProvider;
import javax.xml.bind.JAXBException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

/**
 * Main class of the REST client application.
 *
 * @author smikloso
 */
public class CreaturesRESTClient {

    /**
     * Default URI for the REST service to contact.
     */
    private static final String DEFAULT_URI = "http://localhost:8080/pa165/rest/";

    /**
     * String added to the {@link CreaturesRESTClient#DEFAULT_URI} in order to
     * perform operations upon {@link cz.muni.fi.pa165.creatures.model.Creature}
     * entities.
     */
    private static final String WEAPON_URI_PART = "weapon";

    /**
     * String added to the {@link CreaturesRESTClient#DEFAULT_URI} in order to
     * perform operations upon {@link cz.muni.fi.pa165.creatures.model.Region}
     * entities.
     */
    private static final String REGION_URI_PART = "region";

    public static void main(String[] args) {

        CommandLineParser parser = new PosixParser();
        Options options = OptionsProvider.getInstance().getOptions();

        try {
            CommandLine line = parser.parse(options, args);
            if (!CommandLineValidator.validate(line)) {
                throw new ParseException("Command line arguments are not valid. Please refer the help");
            }

            if (line.hasOption("h")) {
                CreaturesRESTClient.printHelp(options);
                System.exit(0);
            }

            CRUDService crudService;

            String operation = line.getOptionValue("o");
            String uri;
            if (line.hasOption("u")) {
                uri = normalizeURI(line.getOptionValue("u"));
            } else {
                uri = DEFAULT_URI;
            }

            // weapon mode
            if (line.hasOption("w")) {
                crudService = new WeaponCRUDServiceImpl(uri + WEAPON_URI_PART);
                if (operation.equals("C")) {
                    WeaponDTO dto = (WeaponDTO) DTOBuilder.get(WeaponDTO.class, line);
                    crudService.create(dto);
                } else if (operation.equals("R")) {
                    Long id = Long.parseLong(line.getOptionValue("i"));
                    crudService.getById(id);
                } else if (operation.equals("U")) {
                    WeaponDTO dto = (WeaponDTO) DTOBuilder.get(WeaponDTO.class, line);
                    crudService.update(dto);
                } else if (operation.equals("D")) {
                    Long id = Long.parseLong(line.getOptionValue("i"));
                    crudService.delete(id);
                } else if (operation.equals("A")) {
                    crudService.getAll();
                } else if (operation.equals("N")) {
                    crudService.getCount();
                }
            // region mode
            } else if (line.hasOption("r")) {
                crudService = new RegionCRUDServiceImpl(uri + REGION_URI_PART);
                if (operation.equals("C")) {
                    RegionDTO dto = (RegionDTO) DTOBuilder.get(RegionDTO.class, line);
                    crudService.create(dto);
                } else if (operation.equals("R")) {
                    Long id = Long.parseLong(line.getOptionValue("i"));
                    crudService.getById(id);
                } else if (operation.equals("U")) {
                    RegionDTO dto = (RegionDTO) DTOBuilder.get(RegionDTO.class, line);
                    crudService.update(dto);
                } else if (operation.equals("D")) {
                    Long id = Long.parseLong(line.getOptionValue("i"));
                    crudService.delete(id);
                } else if (operation.equals("A")) {
                    crudService.getAll();
                } else if (operation.equals("N")) {
                    crudService.getCount();
                }
            }
        } catch (ParseException ex) {
            CreaturesRESTClient.printHelp(options);
            System.exit(1);
        } catch (IllegalArgumentException ex) {
            System.exit(1);
        } catch (JAXBException ex) {
            System.exit(1);
        } catch (Exception ex) {
            System.exit(1);
        }
    }

    /**
     * This method discards all slashes at the end of the URI address. We do not
     * need to add one because care is taken of it in the business code itself.
     *
     * @param uri URI to normalize
     * @return normalized URI
     */
    private static String normalizeURI(String uri) {
        while (uri.endsWith("/")) {
            uri = uri.substring(0, uri.length() - 1);
        }
        return uri + "/";
    }

    private static void printHelp(Options options) {
        new HelpFormatter().printHelp("[mode] -o [operation] [arguments]...", options);
    }
}
